package com.zj.base.httpclien;

import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;

import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.FileCallBack;
import com.zhy.http.okhttp.callback.StringCallback;
import com.zj.base.base_act.OnHttpDataReceiveIn;
import com.zj.base.cache.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import okhttp3.Call;

/**
 * Created by zhaojie on 2018/4/10.
 */
@SuppressWarnings("ALL")
public class HttpClient<T> {

    private HttpClient(int requstCode, @NonNull OnHttpDataReceiveIn dataIn, Class<T> cls) {
        this.cacheName = dataIn.getClass().getSimpleName() + requstCode + ".txt";
        this.dataIn = dataIn;
        this.cls = cls;
    }

    public void setType(TYPE type) {
        this.type = type;
    }

    public void setTimeOut(long timeOut) {
        this.timeOut = timeOut;
    }

    public void setDataType(DataType dataType) {
        this.dataType = dataType;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setParams(Map<String, String> params) {
        this.params = params;
    }

    public void setCookies(Map<String, String> cookies) {
        this.cookies = cookies;
    }

    public void setDownloadPath(String downloadPath) {
        this.downloadPath = downloadPath;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setUploadKey(String uploadKey) {
        this.uploadKey = uploadKey;
    }

    public OnHttpDataReceiveIn getDataInterface() {
        return dataIn;
    }

    public void setUploadParams(Map<String, File> uploadParams) {
        this.uploadParams = uploadParams;
    }

    public void setCacheSaveEnable(boolean cacheSaveEnable) {
        this.cacheSaveEnable = cacheSaveEnable;
    }

    public void setCacheGetEnable(boolean cacheGetEnable) {
        this.cacheGetEnable = cacheGetEnable;
    }

    public enum DataType {
        LOADMORE, REFRESH, CACHE
    }

    private String TAG = HttpConfig.logTag;

    private OnHttpDataReceiveIn dataIn;

    private final String httpCacheName = "HTTP/";

    public enum TYPE {
        requst, download, upLoad
    }

    private Class<T> cls;

    private TYPE type = TYPE.requst;

    //default time out
    private long timeOut = 5000L;

    private DataType dataType = DataType.REFRESH;

    private String cacheName = "0";

    private String url = null;

    private Map<String, String> params = null;

    private Map<String, String> cookies = null;

    private String downloadPath = "";

    private String fileName = "";

    private String uploadKey = "";

    private boolean cacheSaveEnable = false;

    private boolean cacheGetEnable = false;

    private Map<String, File> uploadParams = null;

    public static <T> GetRequestBuilder<T> get(int reqCode, OnHttpDataReceiveIn dataIn, Class<T> cls) {
        return new GetRequestBuilder(reqCode, new HttpClient(reqCode, dataIn, cls));
    }

    public static <T> PostRequestBuilder<T> post(int reqCode, OnHttpDataReceiveIn dataIn, Class<T> cls) {
        return new PostRequestBuilder(reqCode, new HttpClient(reqCode, dataIn, cls));
    }

    public static <T> GetRequestBuilder<T> get(int reqCode, OnHttpDataReceiveIn dataIn) {
        return new GetRequestBuilder(reqCode, new HttpClient(reqCode, dataIn, String.class));
    }

    public static <T> PostRequestBuilder<T> post(int reqCode, OnHttpDataReceiveIn dataIn) {
        return new PostRequestBuilder(reqCode, new HttpClient(reqCode, dataIn, String.class));
    }

    /**
     * HttpRequestBuilder
     *
     * @param builder
     * @param reqCode
     */
    public void handleData(HttpRequestBuilder<T> builder, int reqCode) {
        if (builder.getMethod() == null) {
            Log.e(TAG, "  error! case: you must use get/set to connect");
            return;
        }
        if (TextUtils.isEmpty(url)) {
            Log.e(TAG, "  error! case: url must not to be null");
            return;
        }
        switch (builder.getMethod()) {
            case get:
                getDataWithGET(reqCode);
                break;
            case post:
                getDateWithPOST(reqCode);
                break;
            default:
                break;
        }
    }

    private void getDataWithGET(final int reqCode) {
        final Map<String, String> cookie = (cookies != null) ? cookies : HttpConfig.getDataSet().getCookie();
        switch (type) {
            case download:
                cheekFileAndDownload(cookie, reqCode);
                break;
            case requst:
                if (cacheGetEnable) {
                    FileUtils.getInstance().take(httpCacheName, cacheName).takeObject(cls, new FileUtils.OnFileTaken<T>() {
                        @Override
                        public void onTaken(boolean isSuccess, T data) {
                            if (isSuccess && data != null)
                                dataIn.onHttpDataReceived(data, reqCode, DataType.CACHE);
                            getRequstByHttp(cookie, reqCode);
                        }
                    });
                } else {
                    getRequstByHttp(cookie, reqCode);
                }
            default:
                break;

        }
    }

    private void getDateWithPOST(final int reqCode) {
        final Map<String, String> cookie = (cookies != null) ? cookies : HttpConfig.getDataSet().getCookie();
        switch (type) {
            case upLoad:
                OkHttpUtils.post().headers(cookie).url(url).params(params).files(uploadKey, uploadParams).build().connTimeOut(timeOut).execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int id) {
                        onDataGot(e.getMessage(), id, reqCode, false, dataType);
                    }

                    @Override
                    public void onResponse(String response, int id) {
                        onDataGot(response, id, reqCode, true, dataType);
                    }

                    @Override
                    public void inProgress(float progress, long total, int id) {
                        dataIn.onHttpProgressChange(reqCode, progress);
                    }
                });
                break;
            case requst:
                if (cacheGetEnable) {
                    FileUtils.getInstance().take(httpCacheName, cacheName).takeObject(cls, new FileUtils.OnFileTaken<T>() {
                        @Override
                        public void onTaken(boolean isSuccess, T data) {
                            if (isSuccess && data != null)
                                dataIn.onHttpDataReceived(data, reqCode, DataType.CACHE);
                            postRequstByHttp(cookie, reqCode);
                        }
                    });
                } else {
                    postRequstByHttp(cookie, reqCode);
                }

                break;
            default:
                break;
        }
    }

    private void getRequstByHttp(Map<String, String> cookie, final int reqCode) {
        OkHttpUtils.get().headers(cookie).url(url).params(params).build().connTimeOut(timeOut).execute(new StringCallback() {
            @Override
            public void onResponse(String response, int id) {
                onDataGot(response, id, reqCode, true, dataType);
            }

            @Override
            public void onError(Call call, Exception e, int id) {
                onDataGot(e.getMessage(), id, reqCode, false, dataType);
            }

            @Override
            public void inProgress(float progress, long total, int id) {
                dataIn.onHttpProgressChange(reqCode, progress);
            }
        });
    }

    private void postRequstByHttp(Map<String, String> cookie, final int reqCode) {
        OkHttpUtils.post().headers(cookie).url(url).params(params).build().connTimeOut(timeOut).execute(new StringCallback() {
            @Override
            public void onError(Call call, Exception e, int id) {
                onDataGot(e.getMessage(), id, reqCode, false, dataType);
            }

            @Override
            public void onResponse(String response, int id) {
                onDataGot(response, id, reqCode, true, dataType);
            }

            @Override
            public void inProgress(float progress, long total, int id) {
                dataIn.onHttpProgressChange(reqCode, progress);
            }
        });
    }

    private void cheekFileAndDownload(Map<String, String> cookie, final int reqCode) {
        if (TextUtils.isEmpty(downloadPath)) {
            throw new NullPointerException("the download path should not be null");
        }
        try {
            File f = new File(downloadPath);
            if (!f.exists()) f.mkdir();
            File file = new File(f, fileName);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
        } catch (IOException e) {
            Log.e(TAG, "the file was never created! cheek your download path and try again!");
        }
        OkHttpUtils.get().headers(cookie).params(params).url(url).build().execute(new FileCallBack(downloadPath, fileName) {
            @Override
            public void onError(Call call, Exception e, int id) {
                dataIn.onHttpError(e.getMessage(), id, reqCode, dataType);
                onFinish();
            }

            @Override
            public void onResponse(File response, int id) {
                dataIn.onHttpDataReceived(response, reqCode, dataType);
                onFinish();
            }

            @Override
            public void inProgress(float progress, long total, int id) {
                dataIn.onHttpProgressChange(reqCode, progress);
            }
        });
    }

    private void onCacheSave(Object reqData) {
        if (!(cacheSaveEnable && dataType == DataType.REFRESH && type == TYPE.requst)) return;
        FileUtils.getInstance().save(httpCacheName, cacheName).saveObject(reqData, new FileUtils.OnFileSave() {
            @Override
            public void onSave(boolean isSuccess, String path) {
                Log.e(TAG, "the cache for :" + path + "  saved " + (isSuccess ? "success" : "fail"));
            }
        });
    }

    private void onDataGot(String response, int id, int reqCode, boolean isSuccess, DataType type) {
        if (isSuccess) {
            Object data = response;
            if (cls != null) {
                data = BaseInfo.init().getInfo(response, cls);
            }
            onCacheSave(data);
            dataIn.onHttpDataReceived(data, reqCode, type);
        } else {
            dataIn.onHttpError(response, id, reqCode, type);
        }
        onFinish();
    }

    private void onFinish() {
        cls = null;
        type = TYPE.requst;
        cacheGetEnable = false;
        cacheSaveEnable = false;
        params = null;
        uploadParams = null;
        cookies = null;
    }
}
